Imports System.Data
Imports System
Imports System.IO
Imports System.Reflection
Imports System.Xml
Imports System.Data.SqlClient
Imports System.Windows.Forms
Imports System.Security.Principal
Imports WWCOETFAttributes

<Assembly: System.Security.Permissions.FileIOPermission(System.Security.Permissions.SecurityAction.RequestMinimum, Unrestricted:=True)> 
<Assembly: CLSCompliant(True)> 
<Assembly: System.ComponentModel.Localizable(True)> 

<CLSCompliant(True)> Public Class UXFrmTestController
#Region "Private Member Variables"
    Private testDriver As Assembly = Nothing
    Private dbServer As String
    Private dbName As String
    Private cn As New SqlConnection
    Private CurrentAssemblyNode As TreeNode
    Private CurrentClassNode As TreeNode
#End Region

#Region "Form Methods"
    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        Dim dlgSplash As New Splash()
        Try
            If CheckForDuplicateProcess("Test Framework Controller") Then
                MessageBox.Show("Another instance of the Test Framework Controller is already running.", "", MessageBoxButtons.OK, MessageBoxIcon.Warning)
                Close()
            End If

            Cursor = Cursors.AppStarting

            dlgSplash.Show()
            Application.DoEvents()

            MSP_EXT_NEW_ASSEMBLYTableAdapter.Connection = cn
            MSP_EXT_NEW_WORKFLOWTableAdapter.Connection = cn
            MSP_EXT_NEW_WORKFLOWCOMMANDTableAdapter.Connection = cn
            MSP_EXT_NEW_TESTTableAdapter.Connection = cn
            MSP_EXT_NEW_COMMANDTableAdapter.Connection = cn
            MSP_EXT_NEW_PARAMTableAdapter.Connection = cn
            MSP_EXT_NEW_AGENTTableAdapter.Connection = cn
            MSP_EXT_NEW_AGENTTESTTableAdapter.Connection = cn
            MSP_EXT_NEW_GetAllAgentTestsTableAdapter.Connection = cn
            MSP_EXT_NEW_GetAllTestsTableAdapter.Connection = cn
            MSP_EXT_NEW_INITIALIZATION_PARAMTableAdapter.Connection = cn

            UpdateDB(My.Settings.WW_COE_Test_FrameworkConnectionString)

            Dim wp As New WindowsPrincipal(WindowsIdentity.GetCurrent())
            Dim username As String = wp.Identity.Name
            Dim index As Integer = username.IndexOf("\")
        Catch ex As Exception
            UpdateStatusBar(ex.Message, True)
        Finally
            dlgSplash.FadeForm()
            dlgSplash.Close()
            Cursor = Cursors.Default
        End Try
    End Sub

    Private Sub UXFrmTestController_FormClosing(ByVal sender As System.Object, ByVal e As System.Windows.Forms.FormClosingEventArgs) Handles MyBase.FormClosing
        If WW_COE_Test_FrameworkDataSet.HasChanges Then
            SaveData()
        End If
    End Sub

    Private Sub SaveData()
        Dim Trans As SqlTransaction = cn.BeginTransaction()
        MSP_EXT_NEW_ASSEMBLYTableAdapter.SetTransaction(Trans)
        MSP_EXT_NEW_WORKFLOWTableAdapter.SetTransaction(Trans)
        MSP_EXT_NEW_WORKFLOWCOMMANDTableAdapter.SetTransaction(Trans)
        MSP_EXT_NEW_TESTTableAdapter.SetTransaction(Trans)
        MSP_EXT_NEW_COMMANDTableAdapter.SetTransaction(Trans)
        MSP_EXT_NEW_PARAMTableAdapter.SetTransaction(Trans)
        MSP_EXT_NEW_AGENTTableAdapter.SetTransaction(Trans)
        MSP_EXT_NEW_AGENTTESTTableAdapter.SetTransaction(Trans)
        MSP_EXT_NEW_INITIALIZATION_PARAMTableAdapter.SetTransaction(Trans)
        Try
            MSP_EXT_NEW_ASSEMBLYTableAdapter.Update(WW_COE_Test_FrameworkDataSet.MSP_EXT_NEW_ASSEMBLY)

            Dim dtWorkflowCommand As WW_COE_Test_FrameworkDataSet.MSP_EXT_NEW_WORKFLOWCOMMANDDataTable = WW_COE_Test_FrameworkDataSet.MSP_EXT_NEW_WORKFLOWCOMMAND.GetChanges(DataRowState.Deleted)
            If Not dtWorkflowCommand Is Nothing Then
                MSP_EXT_NEW_WORKFLOWCOMMANDTableAdapter.Update(dtWorkflowCommand)
            End If

            MSP_EXT_NEW_WORKFLOWTableAdapter.Update(WW_COE_Test_FrameworkDataSet.MSP_EXT_NEW_WORKFLOW)

            dtWorkflowCommand = WW_COE_Test_FrameworkDataSet.MSP_EXT_NEW_WORKFLOWCOMMAND.GetChanges(DataRowState.Added)
            If Not dtWorkflowCommand Is Nothing Then
                MSP_EXT_NEW_WORKFLOWCOMMANDTableAdapter.Update(dtWorkflowCommand)
            End If

            MSP_EXT_NEW_TESTTableAdapter.Update(WW_COE_Test_FrameworkDataSet.MSP_EXT_NEW_TEST)

            Dim dtCommand As WW_COE_Test_FrameworkDataSet.MSP_EXT_NEW_COMMANDDataTable = WW_COE_Test_FrameworkDataSet.MSP_EXT_NEW_COMMAND.GetChanges(DataRowState.Added)
            If Not dtCommand Is Nothing Then
                MSP_EXT_NEW_COMMANDTableAdapter.Update(dtCommand)
            End If

            Dim dtParam As WW_COE_Test_FrameworkDataSet.MSP_EXT_NEW_PARAMDataTable = WW_COE_Test_FrameworkDataSet.MSP_EXT_NEW_PARAM.GetChanges(DataRowState.Added)
            If Not dtParam Is Nothing Then
                MSP_EXT_NEW_PARAMTableAdapter.Update(dtParam)
            End If

            MSP_EXT_NEW_AGENTTableAdapter.Update(WW_COE_Test_FrameworkDataSet.MSP_EXT_NEW_AGENT)
            MSP_EXT_NEW_AGENTTESTTableAdapter.Update(WW_COE_Test_FrameworkDataSet.MSP_EXT_NEW_AGENTTEST)
            MSP_EXT_NEW_INITIALIZATION_PARAMTableAdapter.Update(WW_COE_Test_FrameworkDataSet.MSP_EXT_NEW_INITIALIZATION_PARAM)

            Trans.Commit()
            WW_COE_Test_FrameworkDataSet.AcceptChanges()
        Catch ex As Exception
            Trans.Rollback()
            WW_COE_Test_FrameworkDataSet.RejectChanges()
            MessageBox.Show(ex.Message)
        End Try
    End Sub
#End Region

#Region "Agent Configuration Tab"
    Private Sub btnUpdateConfig_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnUpdateAgents.Click
        MSP_EXT_NEW_AGENTTableAdapter.Fill(WW_COE_Test_FrameworkDataSet.MSP_EXT_NEW_AGENT)
    End Sub
#End Region

#Region "Test Assemblies Tab"
    Private Sub btnBrowseAssembly_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnBrowseAssembly.Click
        If OpenFileDialog1.ShowDialog = Windows.Forms.DialogResult.OK Then
            txtAssemblyName.Text = OpenFileDialog1.FileName
        End If
    End Sub

    Private Sub btnAddAssembly_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnAddAssembly.Click
        Try
            Dim index As Integer = txtAssemblyName.Text.LastIndexOf("\")
            Dim fileName As String = txtAssemblyName.Text.Substring(index + 1, txtAssemblyName.Text.Length - index - 1)
            Dim fullName As String = AppDir() + "\" + fileName
            If Not DuplicateAssembly(fileName) Then
                ' Copy the assembly to the application directory.
                If fullName <> txtAssemblyName.Text Then
                    If File.Exists(fullName) Then
                        File.Delete(fullName)
                    End If
                    File.Copy(txtAssemblyName.Text, fullName)
                End If
                If AddAssembly(tvAssemblies, fileName) = True Then
                    ' Update the DataSet
                    Dim dr As DataRow = WW_COE_Test_FrameworkDataSet.MSP_EXT_NEW_ASSEMBLY.Rows.Add()
                    dr("Name") = fileName
                    dr("FullName") = fullName
                Else
                    txtAssemblyName.Text = ""
                End If
            End If
        Catch ex As Exception
            MessageBox.Show(ex.Message, "", MessageBoxButtons.OK, MessageBoxIcon.Error)
        End Try
    End Sub

    Private Sub btnDeleteAssembly_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnDeleteAssembly.Click
        Try
            ' Update the DataSet.
            For Each dr As DataRow In WW_COE_Test_FrameworkDataSet.MSP_EXT_NEW_ASSEMBLY
                If Not dr.RowState = DataRowState.Deleted Then
                    If dr("Name").ToString = tvAssemblies.SelectedNode.Text Then
                        dr.Delete()
                    End If
                End If
            Next
            ' Update the tree views.
            For Each node As TreeNode In tvAvailableCommands.Nodes
                If node.Text = tvAssemblies.SelectedNode.Text Then
                    node.Remove()
                End If
            Next
            tvAssemblies.SelectedNode.Remove()
            btnDeleteAssembly.Enabled = False
        Catch ex As Exception
            MessageBox.Show(ex.Message, "", MessageBoxButtons.OK, MessageBoxIcon.Error)
        End Try
    End Sub

    Private Sub tvAssemblies_AfterSelect(ByVal sender As System.Object, ByVal e As System.Windows.Forms.TreeViewEventArgs) Handles tvAssemblies.AfterSelect
        Dim topNodeSelected As Boolean = False
        If Not tvAssemblies.SelectedNode Is Nothing Then
            topNodeSelected = tvAssemblies.SelectedNode.Parent Is Nothing
        End If
        btnDeleteAssembly.Enabled = topNodeSelected
    End Sub

    Private Sub txtAssemblyName_TextChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles txtAssemblyName.TextChanged
        btnAddAssembly.Enabled = txtAssemblyName.Text.Length > 0
    End Sub
#End Region

#Region "Workflows Tab"
    Private Sub tvAvailableCommands_AfterSelect(ByVal sender As System.Object, ByVal e As System.Windows.Forms.TreeViewEventArgs) Handles tvAvailableCommands.AfterSelect
        If Not tvAvailableCommands.SelectedNode Is Nothing Then
            Dim CurrentNode As TreeNode = tvAvailableCommands.SelectedNode
            btnAddCmd.Enabled = (CurrentNode.Nodes.Count = 0)
            ' Make sure a command (leaf node) is selected.  Also make sure that the commands list is empty
            ' since commands in a workflow must be in the same assembly and class.
            If CurrentNode.Nodes.Count = 0 And lbWorkflowCommands.Items.Count = 0 Then
                ' Keep the current assembly and class.
                CurrentAssemblyNode = tvAvailableCommands.SelectedNode.Parent.Parent
                CurrentClassNode = tvAvailableCommands.SelectedNode.Parent
                ' Collapse all other branches.
                For Each node As TreeNode In tvAvailableCommands.Nodes
                    If Not node.Text = CurrentAssemblyNode.Text Then
                        node.Collapse()
                    End If
                Next
                For Each node As TreeNode In CurrentAssemblyNode.Nodes
                    If Not node.Text = CurrentClassNode.Text Then
                        node.Collapse()
                    End If
                Next
                ' Only expand the current class commands.
                CurrentNode.EnsureVisible()
            End If
        End If
    End Sub

    Private Sub tvAvailableCommands_BeforeExpand(ByVal sender As System.Object, ByVal e As System.Windows.Forms.TreeViewCancelEventArgs) Handles tvAvailableCommands.BeforeExpand
        e.Cancel = lbWorkflowCommands.Items.Count > 0
    End Sub

    Private Sub tvAvailableCommands_BeforeCollapse(ByVal sender As System.Object, ByVal e As System.Windows.Forms.TreeViewCancelEventArgs) Handles tvAvailableCommands.BeforeCollapse
        e.Cancel = lbWorkflowCommands.Items.Count > 0
    End Sub

    Private Sub lbWorkflowCommands_SelectedIndexChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles lbWorkflowCommands.SelectedIndexChanged
        btnUp.Enabled = lbWorkflowCommands.SelectedIndex > -1
        btnDown.Enabled = lbWorkflowCommands.SelectedIndex > -1
        btnDeleteCmd.Enabled = lbWorkflowCommands.SelectedIndex > -1
    End Sub

    Private Sub btnAddWorkflow_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnAddWorkflow.Click
        Try
            ' Make sure the workflow name doesn't already exist.
            For index As Integer = 0 To lbWorkflows.Items.Count - 1
                If lbWorkflows.Items(index) = txtWorkflowName.Text Then
                    MessageBox.Show(txtWorkflowName.Text + " is already used as a workflow name.  Select another one.", "", MessageBoxButtons.OK, MessageBoxIcon.Error)
                    Return
                End If
            Next

            If lbWorkflowCommands.Items.Count = 0 Then
                MessageBox.Show("The " + txtWorkflowName.Text + " workflow does not contain any commands.", "", MessageBoxButtons.OK, MessageBoxIcon.Error)
                Return
            End If

            lbWorkflows.Items.Add(txtWorkflowName.Text)
            ' Update the DataSet
            Dim dr As DataRow = WW_COE_Test_FrameworkDataSet.MSP_EXT_NEW_WORKFLOW.Rows.Add()
            dr("Name") = txtWorkflowName.Text
            dr("AssemblyName") = CurrentAssemblyNode.Text
            dr("ClassName") = CurrentClassNode.Text
            dr("FullAssemblyName") = CurrentAssemblyNode.Tag
            ' Add the workflow commands.
            For index As Integer = 0 To lbWorkflowCommands.Items.Count - 1
                Dim dr1 As DataRow = WW_COE_Test_FrameworkDataSet.MSP_EXT_NEW_WORKFLOWCOMMAND.Rows.Add()
                dr1("CommandName") = lbWorkflowCommands.Items(index)
                dr1("Name") = dr("Name")
            Next

            ' Clear the values in the UI.
            txtWorkflowName.Text = ""
            lbWorkflowCommands.Items.Clear()
        Catch ex As Exception
            MessageBox.Show(ex.Message, "", MessageBoxButtons.OK, MessageBoxIcon.Error)
        End Try
    End Sub

    Private Sub btnDeleteWorkflow_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnDeleteWorkflow.Click
        Try
            ' Update the DataSet.
            Dim dr As DataRow
            For index As Integer = WW_COE_Test_FrameworkDataSet.MSP_EXT_NEW_WORKFLOW.Rows.Count - 1 To 0 Step -1
                'For Each dr As DataRow In WW_COE_Test_FrameworkDataSet.MSP_EXT_NEW_WORKFLOW
                dr = WW_COE_Test_FrameworkDataSet.MSP_EXT_NEW_WORKFLOW.Rows(index)
                If Not dr.RowState = DataRowState.Deleted Then
                    If dr("Name").ToString = lbWorkflows.Items(lbWorkflows.SelectedIndex).ToString Then
                        dr.Delete()
                    End If
                End If
            Next

            Dim dr1 As DataRow
            For index As Integer = WW_COE_Test_FrameworkDataSet.MSP_EXT_NEW_WORKFLOWCOMMAND.Rows.Count - 1 To 0 Step -1
                'For Each dr1 As DataRow In WW_COE_Test_FrameworkDataSet.MSP_EXT_NEW_WORKFLOWCOMMAND
                dr1 = WW_COE_Test_FrameworkDataSet.MSP_EXT_NEW_WORKFLOWCOMMAND.Rows(index)
                If Not dr1.RowState = DataRowState.Deleted Then
                    If dr1("Name").ToString = lbWorkflows.Items(lbWorkflows.SelectedIndex).ToString Then
                        dr1.Delete()
                    End If
                End If
            Next
            lbWorkflows.Items.RemoveAt(lbWorkflows.SelectedIndex)
            If lbWorkflows.Items.Count > 0 Then
                lbWorkflows.SelectedIndex = 0
            End If
        Catch ex As Exception
            MessageBox.Show(ex.Message, "", MessageBoxButtons.OK, MessageBoxIcon.Error)
        End Try
    End Sub

    Private Sub btnEditWorkflow_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnSaveWorkflow.Click
        Dim dr As DataRow = Nothing
        Dim found As Boolean = False
        For Each dr In WW_COE_Test_FrameworkDataSet.MSP_EXT_NEW_WORKFLOW.Rows
            If dr("Name") = txtWorkflowName.Text Then
                found = True
                Exit For
            End If
        Next
        If Not found Then Return

        ' Remove the existing workflow commands.
        Dim dr1 As DataRow
        For index As Integer = WW_COE_Test_FrameworkDataSet.MSP_EXT_NEW_WORKFLOWCOMMAND.Rows.Count - 1 To 0 Step -1
            'For Each dr1 As DataRow In WW_COE_Test_FrameworkDataSet.MSP_EXT_NEW_WORKFLOWCOMMAND
            dr1 = WW_COE_Test_FrameworkDataSet.MSP_EXT_NEW_WORKFLOWCOMMAND.Rows(index)
            If Not dr1.RowState = DataRowState.Deleted Then
                If dr1("Name").ToString = lbWorkflows.Items(lbWorkflows.SelectedIndex).ToString Then
                    dr1.Delete()
                End If
            End If
        Next
        ' Add the workflow commands.
        For index As Integer = 0 To lbWorkflowCommands.Items.Count - 1
            dr1 = WW_COE_Test_FrameworkDataSet.MSP_EXT_NEW_WORKFLOWCOMMAND.Rows.Add()
            dr1("CommandName") = lbWorkflowCommands.Items(index)
            dr1("Name") = dr("Name")
        Next
    End Sub

    Private Sub btnUp_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnUp.Click
        If lbWorkflowCommands.SelectedIndex > 0 Then
            Dim cmd As String = lbWorkflowCommands.Items(lbWorkflowCommands.SelectedIndex).ToString
            Dim index As Integer = lbWorkflowCommands.SelectedIndex
            lbWorkflowCommands.Items.Insert(index - 1, cmd)
            lbWorkflowCommands.Items.RemoveAt(lbWorkflowCommands.SelectedIndex)
            lbWorkflowCommands.SelectedIndex = index - 1
        End If
    End Sub

    Private Sub btnDown_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnDown.Click
        If lbWorkflowCommands.SelectedIndex < lbWorkflowCommands.Items.Count - 1 Then
            Dim cmd As String = lbWorkflowCommands.Items(lbWorkflowCommands.SelectedIndex).ToString
            Dim index As Integer = lbWorkflowCommands.SelectedIndex
            lbWorkflowCommands.Items.Insert(index + 2, cmd)
            lbWorkflowCommands.Items.RemoveAt(lbWorkflowCommands.SelectedIndex)
            lbWorkflowCommands.SelectedIndex = index + 1
        End If
    End Sub

    Private Sub btnAddCmd_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnAddCmd.Click
        AddCommand()
    End Sub

    Private Sub btnDeleteCmd_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnDeleteCmd.Click
        lbWorkflowCommands.Items.RemoveAt(lbWorkflowCommands.SelectedIndex)
    End Sub

    Private Sub txtWorkflowName_TextChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles txtWorkflowName.TextChanged
        btnAddWorkflow.Enabled = txtWorkflowName.Text.Length > 0
    End Sub

    Private Sub lbWorkflows_SelectedIndexChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles lbWorkflows.SelectedIndexChanged
        btnDeleteWorkflow.Enabled = lbWorkflows.SelectedIndex > -1
        btnSaveWorkflow.Enabled = lbWorkflows.SelectedIndex > -1
        ' Display the existing worklfow commands.
        lbWorkflowCommands.Items.Clear()
        If lbWorkflows.SelectedItem Is Nothing Then
            Me.btnDeleteWorkflow.Enabled = False
            txtWorkflowName.Text = ""
            Exit Sub
        End If
        Me.btnDeleteWorkflow.Enabled = True
        For Each dr As DataRow In WW_COE_Test_FrameworkDataSet.MSP_EXT_NEW_WORKFLOWCOMMAND.Rows
            If Not dr.RowState = DataRowState.Deleted Then
                If dr("Name").ToString = lbWorkflows.SelectedItem.ToString Then
                    lbWorkflowCommands.Items.Add(dr("CommandName").ToString)
                End If
            End If
        Next
        txtWorkflowName.Text = lbWorkflows.SelectedItem.ToString
    End Sub

    Private Sub tvAvailableCommands_DoubleClick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles tvAvailableCommands.DoubleClick
        If tvAvailableCommands.SelectedNode Is Nothing Then
            Exit Sub
        End If
        If tvAvailableCommands.SelectedNode.Nodes.Count = 0 Then
            AddCommand()
        End If
    End Sub

    Private Sub AddCommand()
        Dim index As Integer = tvAvailableCommands.SelectedNode.Text.IndexOf("(")
        lbWorkflowCommands.Items.Add(tvAvailableCommands.SelectedNode.Text.Substring(0, index))
    End Sub
#End Region

#Region "Test Tab"
    Private Sub btnUnselectAllUsers_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnUnselectAllUsers.Click
        For Each dr As DataGridViewRow In dgSessions.Rows
            dr.Selected = False
        Next
    End Sub

    Private Sub btnSelectAllUsers_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnSelectAllUsers.Click
        For Each dr As DataGridViewRow In dgSessions.Rows
            dr.Selected = True
        Next
    End Sub

    Private Sub cbWorkflow_SelectedValueChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles cbWorkflow.SelectedValueChanged
        Dim fullAssemblyName As String = ""
        ' Display the assembly and class for the selected workflow.
        For Each dr As DataRow In WW_COE_Test_FrameworkDataSet.MSP_EXT_NEW_WORKFLOW.Rows
            If Not dr.RowState = DataRowState.Deleted Then
                If dr("Name").ToString = cbWorkflow.Text Then
                    txtAssembly.Text = dr("AssemblyName").ToString
                    txtClass.Text = dr("ClassName").ToString
                End If
            End If
        Next

        ' Generate a unique Test name as a default.
        txtTestName.Text = "Test " + DateTime.Now.ToShortDateString + " " + DateTime.Now.ToLongTimeString

        ' Display the commands in the workflow.
        ' Load the assembly.
        fullAssemblyName = AppDir() + "\" + txtAssembly.Text
        If Not File.Exists(fullAssemblyName) Then
            Exit Sub
        End If
        testDriver = Assembly.LoadFile(fullAssemblyName)

        Dim nodeParam As TreeNode
        Dim nodeCmd As TreeNode
        Dim itemStr As String
        Dim classType As Type
        tvCommands.Nodes.Clear()
        For Each dr As DataRow In WW_COE_Test_FrameworkDataSet.MSP_EXT_NEW_WORKFLOWCOMMAND.Rows
            If Not dr.RowState = DataRowState.Deleted Then
                If dr("Name").ToString = cbWorkflow.Text Then
                    classType = testDriver.GetType(txtClass.Text)
                    If Not classType Is Nothing Then
                        Dim mi As MethodInfo = FindMethod(dr("CommandName").ToString(), classType, testDriver)
                        If Not mi Is Nothing Then
                            ' Build a list of the available test methods in the class.
                            itemStr = GetParamList(mi)
                            nodeCmd = tvCommands.Nodes.Add(itemStr)
                            nodeCmd.Tag = mi.Name
                            Dim paramText As String
                            ' Allow each individual param to be edited.
                            For Each pi As ParameterInfo In mi.GetParameters
                                Dim cpi As New CmdParamInfo
                                cpi.pi = pi
                                ' Get custom WWCOETF attributes for parameters.  These
                                ' tell is required and provide default values.  If not found
                                ' the param is required and has no default.
                                cpi.attribs = mi.GetCustomAttributes(False)
                                ' Append the default value if available.
                                paramText = pi.Name + "=" + GetDefaultValue(cpi.attribs, pi.Name)
                                cpi.value = GetDefaultValue(cpi.attribs, pi.Name)
                                nodeParam = nodeCmd.Nodes.Add(paramText)
                                nodeParam.Tag = cpi
                            Next
                        End If
                    End If
                End If
            End If
        Next
        tvCommands.ExpandAll()

        ' Build the tree of constructors and any params.
        Dim nodeConstructor As TreeNode
        tvConstructors.Nodes.Clear()
        classType = testDriver.GetType(txtClass.Text)
        If Not classType Is Nothing Then
            For Each ci As ConstructorInfo In classType.GetConstructors
                ' Build a list of the available constructors in the class.
                itemStr = GetParamList(ci)
                nodeConstructor = tvConstructors.Nodes.Add("Initialize" + itemStr)
                nodeConstructor.Tag = ci.Name
                For Each pi As ParameterInfo In ci.GetParameters
                    nodeParam = nodeConstructor.Nodes.Add(pi.Name + "=")
                    Dim cpi As New CmdParamInfo
                    cpi.pi = pi
                    cpi.value = GetDefaultValue(cpi.attribs, pi.Name)
                    nodeParam.Tag = cpi
                Next
            Next
            tvConstructors.ExpandAll()
        End If
    End Sub

    Private Function FindMethod(ByVal methodName As String, ByVal classType As Type, ByVal testDriver As Assembly) As MethodInfo
        For Each mi As MethodInfo In classType.GetMethods()
            If testDriver.GetType(txtClass.Text).ToString() = mi.DeclaringType.ToString() Then
                If mi.Name = methodName Then
                    Return mi
                End If
            End If
        Next
        Return Nothing
    End Function

    Private Sub tvCommands_AfterSelect(ByVal sender As System.Object, ByVal e As System.Windows.Forms.TreeViewEventArgs) Handles tvCommands.AfterSelect
        GetNodeParams(tvCommands)
    End Sub

    Private Sub tvConstructors_AfterSelect(ByVal sender As System.Object, ByVal e As System.Windows.Forms.TreeViewEventArgs) Handles tvConstructors.AfterSelect
        GetNodeParams(tvConstructors)
    End Sub

    Private Sub GetNodeParams(ByVal tv As TreeView)
        If Not tv.SelectedNode Is Nothing Then
            tv.LabelEdit = False
            ' Make sure the slected node is a parameter.
            If tv.SelectedNode.Level = 1 Then
                ' Display the dialog to let the user enter the value.  Could use
                ' the editing capability of the tree but kind of klunky.
                Dim dlg As New CmdParams
                Dim cpi As CmdParamInfo = tv.SelectedNode.Tag
                dlg.txtName.Text = cpi.pi.Name
                dlg.txtType.Text = cpi.pi.ParameterType.ToString
                dlg.Required = GetRequired(cpi.attribs, cpi.pi.Name)
                If cpi.pi.ParameterType.Name = "Boolean" Then dlg.IsBool = True Else dlg.IsBool = False

                If cpi.edited = False Then
                    dlg.ParamValue = GetDefaultValue(cpi.attribs, cpi.pi.Name)
                Else
                    dlg.ParamValue = cpi.value
                End If
                If dlg.ShowDialog(Me) = Windows.Forms.DialogResult.OK Then
                    cpi.value = dlg.ParamValue
                    cpi.edited = True
                    tv.SelectedNode.Text = cpi.pi.Name + "=" + cpi.value
                End If
                tv.SelectedNode = Nothing
            End If
        End If
    End Sub

    Private Function GetDefaultValue(ByVal attribs As Array, ByVal name As String) As String
        If Not attribs Is Nothing Then
            For Each attrib As WWCOETFParameter In attribs
                If attrib.Name = name Then
                    Return attrib.DefaultValue
                End If
            Next
        End If
        Return ""
    End Function

    Private Function GetRequired(ByVal attribs As Array, ByVal name As String) As Boolean
        If Not attribs Is Nothing Then
            For Each attrib As WWCOETFParameter In attribs
                If attrib.Name = name Then
                    Return attrib.Required
                End If
            Next
        End If
        Return True
    End Function

    Private Sub chkExecuteOnce_CheckedChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles chkExecuteOnce.CheckedChanged
        txtDuration.Enabled = Not chkExecuteOnce.Checked
    End Sub

    Private Sub chkExecuteImmediate_CheckedChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles chkExecuteImmediate.CheckedChanged
        dtpStart.Enabled = Not chkExecuteImmediate.Checked
    End Sub

    Private Sub btnSubmitTest_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnSubmitTest.Click
        ' Make sure required fields are supplied.
        If txtTestName.Text.Length = 0 Then
            MessageBox.Show("Test name is required.", "", MessageBoxButtons.OK, MessageBoxIcon.Error)
            txtTestName.Focus()
            Exit Sub
        End If
        If cbWorkflow.Text.Length = 0 Then
            MessageBox.Show("Workflow name is required.", "", MessageBoxButtons.OK, MessageBoxIcon.Error)
            cbWorkflow.Focus()
            Exit Sub
        End If
        If chkExecuteOnce.Checked = False And txtDuration.Text.Length = 0 Then
            MessageBox.Show("Duration is required if Execute Once is not checked.", "", MessageBoxButtons.OK, MessageBoxIcon.Error)
            txtDuration.Focus()
            Exit Sub
        End If
        If dgSessions.SelectedRows.Count = 0 Then
            MessageBox.Show("At least one test user must be selected.", "", MessageBoxButtons.OK, MessageBoxIcon.Error)
            txtDuration.Focus()
            Exit Sub
        End If
        Dim cpi As CmdParamInfo
        For Each nodeConstructor As TreeNode In tvConstructors.Nodes
            For Each nodeParam As TreeNode In nodeConstructor.Nodes
                cpi = nodeParam.Tag
                If cpi.value Is Nothing And GetRequired(cpi.attribs, cpi.pi.Name) Then
                    MessageBox.Show("The initializer parameter value for " + cpi.pi.Name + " must be entered.", "", MessageBoxButtons.OK, MessageBoxIcon.Error)
                    tvConstructors.Focus()
                    Exit Sub
                End If
            Next
        Next
        For Each nodeCmd As TreeNode In tvCommands.Nodes
            For Each nodeParam As TreeNode In nodeCmd.Nodes
                cpi = nodeParam.Tag
                If cpi.value Is Nothing And GetRequired(cpi.attribs, cpi.pi.Name) Then
                    MessageBox.Show("The parameter value for " + cpi.pi.Name + " in " + nodeCmd.Text + " must be entered.", "", MessageBoxButtons.OK, MessageBoxIcon.Error)
                    tvCommands.Focus()
                    Exit Sub
                End If
            Next
        Next
        ' Add the test.
        Dim dr As DataRow = WW_COE_Test_FrameworkDataSet.MSP_EXT_NEW_TEST.Rows.Add()
        dr("Name") = txtTestName.Text
        dr("Description") = txtDescription.Text
        dr("WorkflowName") = cbWorkflow.Text
        dr("AssemblyName") = txtAssembly.Text
        dr("ClassName") = txtClass.Text
        dr("DateSubmitted") = DateTime.Now.ToLongDateString()
        If txtDuration.Text.Trim.Length > 0 Then
            dr("Duration") = Convert.ToInt32(txtDuration.Text)
        Else
            dr("Duration") = 0
        End If
        dr("ExecuteOnce") = chkExecuteOnce.Checked
        dr("StartTime") = dtpStart.Text
        dr("ExecuteImmediately") = chkExecuteImmediate.Checked
        ' Add the commands for the test.
        Dim cmdSeq As Integer = 1
        Dim paramSeq As Integer
        For Each nodeCmd As TreeNode In tvCommands.Nodes
            dr = WW_COE_Test_FrameworkDataSet.MSP_EXT_NEW_COMMAND.Rows.Add()
            dr("Name") = nodeCmd.Tag
            dr("TestName") = txtTestName.Text
            dr("Sequence") = cmdSeq
            paramSeq = 1
            For Each nodeParam As TreeNode In nodeCmd.Nodes
                cpi = nodeParam.Tag
                dr = WW_COE_Test_FrameworkDataSet.MSP_EXT_NEW_PARAM.Rows.Add()
                dr("Name") = cpi.pi.Name
                dr("Type") = cpi.pi.ParameterType.ToString
                dr("Value") = cpi.value
                dr("CommandSequence") = cmdSeq
                dr("TestName") = txtTestName.Text
                dr("Sequence") = paramSeq
                paramSeq = paramSeq + 1
            Next
            cmdSeq = cmdSeq + 1
        Next
        ' Add the entries for each test agent.
        'WW_COE_Test_FrameworkDataSet.MSP_EXT_NEW_AGENT.Rows.Clear()
        For Each dgvr As DataGridViewRow In dgSessions.SelectedRows
            dr = WW_COE_Test_FrameworkDataSet.MSP_EXT_NEW_AGENTTEST.Rows.Add()
            dr("Session") = dgvr.Cells(3).Value.ToString()
            dr("TestName") = txtTestName.Text
            dgvr.Selected = False
        Next

        ' Add any initialization parameters for the test.
        ' Assume that there is only only constructor.
        If tvConstructors.Nodes.Count > 0 Then
            paramSeq = 1
            For Each nodeParam As TreeNode In tvConstructors.Nodes(0).Nodes
                dr = WW_COE_Test_FrameworkDataSet.MSP_EXT_NEW_INITIALIZATION_PARAM.Rows.Add()
                cpi = nodeParam.Tag
                dr("Name") = cpi.pi.Name
                dr("Type") = cpi.pi.ParameterType.ToString
                dr("Value") = cpi.value
                dr("TestName") = txtTestName.Text
                dr("Sequence") = paramSeq
                paramSeq = paramSeq + 1
            Next
        End If

        SaveData()
        MSP_EXT_NEW_AGENTTableAdapter.Fill(WW_COE_Test_FrameworkDataSet.MSP_EXT_NEW_AGENT)

        UpdateStatusBar(txtTestName.Text + " submitted for execution.", False)

        ' Generate a unique Test name as a default.
        txtTestName.Text = "Test " + DateTime.Now.ToShortDateString + " " + DateTime.Now.ToLongTimeString
    End Sub
#End Region

#Region "Test Results Tab"
    Private Sub MSP_EXT_NEW_GetAllTestsDataGridView_SelectionChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MSP_EXT_NEW_GetAllTestsDataGridView.SelectionChanged
        ' Filter based uopn the selected test.
        Dim dgv As DataGridView = sender
        If Not dgv.CurrentRow Is Nothing Then
            MSP_EXT_NEW_GetAllAgentTestsBindingSource.Filter = "TestID=" + dgv.CurrentRow.Cells("ID").Value.ToString
        End If
    End Sub
#End Region

#Region "Tab Control"
    Private Sub TabControl1_Selected(ByVal sender As System.Object, ByVal e As System.Windows.Forms.TabControlEventArgs) Handles TabControl1.Selected
        Try
            Cursor = Cursors.WaitCursor
            Select Case e.TabPage.Text
                Case "Test Assemblies"
                    tvAssemblies.Nodes.Clear()
                    For Each dr As DataRow In WW_COE_Test_FrameworkDataSet.MSP_EXT_NEW_ASSEMBLY
                        If Not dr.RowState = DataRowState.Deleted Then
                            AddAssembly(tvAssemblies, dr("Name").ToString)
                        End If
                    Next

                Case "Workflows"
                    lbWorkflows.Items.Clear()
                    For Each dr As DataRow In WW_COE_Test_FrameworkDataSet.MSP_EXT_NEW_WORKFLOW
                        If Not dr.RowState = DataRowState.Deleted Then
                            lbWorkflows.Items.Add(dr("Name"))
                        End If
                    Next
                    tvAvailableCommands.Nodes.Clear()
                    For Each dr As DataRow In WW_COE_Test_FrameworkDataSet.MSP_EXT_NEW_ASSEMBLY
                        If Not dr.RowState = DataRowState.Deleted Then
                            AddAssembly(tvAvailableCommands, dr("Name").ToString)
                        End If
                    Next
                    CurrentAssemblyNode = tvAvailableCommands.Nodes(0)
                    CurrentClassNode = tvAvailableCommands.Nodes(0).Nodes(0)

                Case "Test"
                    ' Populate the workflow list.
                    cbWorkflow.Items.Clear()
                    For Each dr As DataRow In WW_COE_Test_FrameworkDataSet.MSP_EXT_NEW_WORKFLOW
                        If Not dr.RowState = DataRowState.Deleted Then
                            cbWorkflow.Items.Add(dr("Name"))
                        End If
                    Next

                Case "Test Results"
                    ' Refresh the data in the grids.
                    MSP_EXT_NEW_GetAllTestsTableAdapter.Fill(WW_COE_Test_FrameworkDataSet.MSP_EXT_NEW_GetAllTests)
            End Select
        Catch ex As Exception
            MessageBox.Show(ex.Message)
        Finally
            Cursor = Cursors.Default
        End Try
    End Sub
#End Region

#Region "Menu Handlers"
    Private Sub menuSaveChanges_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles menuSaveChanges.Click
        SaveData()
    End Sub

    Private Sub menuRejectChanges_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles menuRejectChanges.Click
        WW_COE_Test_FrameworkDataSet.RejectChanges()
    End Sub

    Private Sub menuExit_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles menuExit.Click
        If WW_COE_Test_FrameworkDataSet.HasChanges() Then
            If MessageBox.Show("Do you want to save the changes?", "", MessageBoxButtons.YesNo, MessageBoxIcon.Question) = Windows.Forms.DialogResult.Yes Then
                SaveData()
            End If
        End If
        Close()
    End Sub

    Private Sub menuSettings_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles menuSettings.Click
        Dim dlg As New SettingsDialog
        If dlg.ShowDialog() = Windows.Forms.DialogResult.OK Then
            UpdateDB(dlg.ConnectionString)
        End If
    End Sub

    Private Sub menuClearTestResults_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles menuClearTestResults.Click
        If MessageBox.Show("Are you sure you want to clear all test results?", "", MessageBoxButtons.YesNo, MessageBoxIcon.Question) = Windows.Forms.DialogResult.Yes Then
            Dim cmd As SqlCommand = New SqlCommand("MSP_EXT_NEW_ClearTestData", cn)
            cmd.CommandType = CommandType.StoredProcedure
            cmd.ExecuteNonQuery()
        End If
    End Sub
#End Region

#Region "Utilities"
    Private Function CheckForDuplicateProcess(ByVal processName As String) As Boolean
        'function returns true if it finds more than one 'processName' running
        Dim Procs() As Process
        Dim proc As Process    'get ALL processes running on this machine in all desktops
        'this also finds all services running as well.

        Procs = Process.GetProcesses()
        Dim count As Integer = 0
        For Each proc In Procs
            If proc.ProcessName.ToString.Equals(processName) Then
                count += 1
            End If
        Next proc
        If count > 1 Then
            Return True
        Else
            Return False
        End If
    End Function

    Private Sub UpdateDB(ByVal connStr As String)
        Try
            Cursor = Cursors.WaitCursor

            If cn.State = ConnectionState.Open Then
                cn.Close()
            End If
            cn.ConnectionString = connStr
            txtConnStr.Text = connStr
            cn.Open()

            ' Load any existing test assembly information.
            WW_COE_Test_FrameworkDataSet.EnforceConstraints = False
            MSP_EXT_NEW_ASSEMBLYTableAdapter.Fill(WW_COE_Test_FrameworkDataSet.MSP_EXT_NEW_ASSEMBLY)
            MSP_EXT_NEW_WORKFLOWTableAdapter.Fill(WW_COE_Test_FrameworkDataSet.MSP_EXT_NEW_WORKFLOW)
            MSP_EXT_NEW_WORKFLOWCOMMANDTableAdapter.Fill(WW_COE_Test_FrameworkDataSet.MSP_EXT_NEW_WORKFLOWCOMMAND)
            MSP_EXT_NEW_TESTTableAdapter.Fill(WW_COE_Test_FrameworkDataSet.MSP_EXT_NEW_TEST)
            MSP_EXT_NEW_COMMANDTableAdapter.Fill(WW_COE_Test_FrameworkDataSet.MSP_EXT_NEW_COMMAND)
            MSP_EXT_NEW_PARAMTableAdapter.Fill(WW_COE_Test_FrameworkDataSet.MSP_EXT_NEW_PARAM)
            MSP_EXT_NEW_AGENTTableAdapter.Fill(WW_COE_Test_FrameworkDataSet.MSP_EXT_NEW_AGENT)
            MSP_EXT_NEW_AGENTTESTTableAdapter.Fill(WW_COE_Test_FrameworkDataSet.MSP_EXT_NEW_AGENTTEST)
            MSP_EXT_NEW_GetAllAgentTestsTableAdapter.Fill(WW_COE_Test_FrameworkDataSet.MSP_EXT_NEW_GetAllAgentTests)
            MSP_EXT_NEW_GetAllTestsTableAdapter.Fill(WW_COE_Test_FrameworkDataSet.MSP_EXT_NEW_GetAllTests)
            MSP_EXT_NEW_GetAllCommandResultsTableAdapter.Fill(WW_COE_Test_FrameworkDataSet.MSP_EXT_NEW_GetAllCommandResults)

            TabControl1.Enabled = True
            UpdateStatusBar("Connected to the database successfully.", False)
        Catch ex As Exception
            TabControl1.Enabled = False
            UpdateStatusBar("Failed to connect to the database.", True)
        Finally
            Cursor = Cursors.Default
        End Try
    End Sub

    Private Sub UpdateStatusBar(ByVal msg As String, ByVal err As Boolean)
        ToolStripStatusLabel1.Text = msg
        If err Then
            ToolStripStatusLabel1.ForeColor = Color.Red
        Else
            ToolStripStatusLabel1.ForeColor = Color.Black
        End If
        Application.DoEvents()
    End Sub

    Private Sub ParseConnectionString(ByVal connstr As String)
        Dim front As Integer = connstr.IndexOf("Data Source=")
        front = front + 12
        Dim back As Integer = connstr.IndexOf(";", front)
        dbServer = connstr.Substring(front, back - front)
        front = connstr.IndexOf("Initial Catalog=")
        front = front + 16
        back = connstr.IndexOf(";", front)
        dbName = connstr.Substring(front, back - front)
    End Sub

    Private Function AppDir() As String
        ' Look in the application directory for any test assemblies.
        Dim index As Integer = Application.ExecutablePath.LastIndexOf("\")
        Dim appDirectory As String = Application.ExecutablePath.Substring(0, index)
        Return appDirectory
    End Function

    Private Function AddAssembly(ByVal tv As TreeView, ByVal Name As String) As Boolean
        Try
            ' Add the assembly name to the root.
            Dim fullName As String = AppDir() + "\" + Name
            ' Load the assembly.
            If File.Exists(fullName) Then
                testDriver = Assembly.LoadFile(fullName)
            End If
            If testDriver Is Nothing Then
                MessageBox.Show("Could not load " + fullName + ".", "", MessageBoxButtons.OK, MessageBoxIcon.Warning)
                Return False
            End If

            Dim root As TreeNode = tv.Nodes.Add(Name)
            root.Tag = fullName
            ' Add a child node for each test class in the assembly.
            For Each typ As Type In testDriver.GetExportedTypes()
                If typ.IsClass Then
                    Dim classType As Type = testDriver.GetType(typ.Namespace + "." + typ.Name)
                    If classType Is Nothing Then Continue For
                    ' Check for the WWCOETFClass attribute.  If not found then don't display.
                    If IsWWCOETFClass(typ) = False Then Continue For
                    ' Only allow one public constructor.
                    If classType.GetConstructors.GetLength(0) > 1 Then
                        MessageBox.Show("The class " + typ.Namespace + "." + typ.Name + " contains more than 1 public constructor.", "", MessageBoxButtons.OK, MessageBoxIcon.Warning)
                        Continue For
                    End If
                    ' Check if the class has a Dispose method.
                    If classType.GetMethod("Dispose") Is Nothing Then
                        MessageBox.Show("The class " + typ.Namespace + "." + typ.Name + " does not contain a Dispose method. Test classes should be derived from IDisposable.", "", MessageBoxButtons.OK, MessageBoxIcon.Warning)
                        Continue For
                    End If
                    Dim nodeClass As TreeNode = root.Nodes.Add(typ.Namespace + "." + typ.Name)
                    If Not classType Is Nothing Then
                        ' Build a list of the available test methods in the class.
                        For Each mi As MethodInfo In classType.GetMethods()
                            If testDriver.GetType(typ.Namespace + "." + typ.Name).ToString() = mi.DeclaringType.ToString() Then
                                ' Don't display the Dispose() method.  It is only used internally to clean up.
                                If mi.Name <> "Dispose" Then
                                    ' Build the parameter list for the display.
                                    nodeClass.Nodes.Add(GetParamList(mi))
                                End If
                            End If
                        Next
                    End If
                End If
            Next
            ' If no classes were found with the WWCOETF attribute then remove it.
            If root.Nodes.Count = 0 Then
                root.Remove()
                MessageBox.Show("No classes with the WWCOETF attribute were found in " + Name + ".")
                Return False
            Else
                root.ExpandAll()
            End If
            Return True
        Catch ex As Exception
            UpdateStatusBar(ex.Message, True)
            Return False
        End Try
    End Function

    Private Function IsWWCOETFClass(ByVal typ As Type) As Boolean
        Dim attribs As Array = typ.GetCustomAttributes(False)
        If attribs.Length = 0 Then Return False
        For Each attrib As Object In attribs
            If attrib.GetType().Name = "WWCOETFClass" Then Return True
        Next
        Return False
    End Function

    Private Function DuplicateAssembly(ByVal fileName As String) As Boolean
        For Each node As TreeNode In tvAssemblies.Nodes
            If node.Text = fileName Then
                Return True
            End If
        Next
        Return False
    End Function

    Private Function GetParamList(ByVal mi As MethodInfo) As String
        ' Build the parameter list for the display.
        Dim numParams As Integer = 0
        Dim itemStr As String = mi.Name + "("
        For Each pi As ParameterInfo In mi.GetParameters
            numParams = numParams + 1
            If numParams > 1 Then
                itemStr = itemStr + ", "
            End If
            itemStr = String.Concat(itemStr, pi.Name, " as ", pi.ParameterType)
        Next
        itemStr = itemStr + ")"
        Return itemStr
    End Function

    Private Function GetParamList(ByVal ci As ConstructorInfo) As String
        ' Build the parameter list for the display.
        Dim numParams As Integer = 0
        Dim itemStr As String = "("
        For Each pi As ParameterInfo In ci.GetParameters
            numParams = numParams + 1
            If numParams > 1 Then
                itemStr = itemStr + ", "
            End If
            itemStr = String.Concat(itemStr, pi.Name, " as ", pi.ParameterType)
        Next
        itemStr = itemStr + ")"
        Return itemStr
    End Function
#End Region
End Class


